package com.uduemc.biso.node.core.utils;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.lang.ArrayUtils;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.uduemc.biso.core.extities.center.Host;
import com.uduemc.biso.core.utils.CryptoJava;
import com.uduemc.biso.node.core.entities.HConfig;
import com.uduemc.biso.node.core.entities.HDomain;
import com.uduemc.biso.node.core.entities.SArticle;
import com.uduemc.biso.node.core.entities.SArticleSlug;
import com.uduemc.biso.node.core.entities.SCategories;
import com.uduemc.biso.node.core.entities.SPage;
import com.uduemc.biso.node.core.entities.SPdtable;
import com.uduemc.biso.node.core.entities.SProduct;
import com.uduemc.biso.node.core.entities.SSystemItemCustomLink;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.URLUtil;
import cn.hutool.crypto.SecureUtil;

/**
 * 纯工具方法 制作站点端的url链接
 * 
 * @author guanyi
 *
 */
public class SiteUrlUtil {

	public static String SysDomainAccessVaildUri = "/biso/sysdomain-access.html";

	// 本地开发模式下通过系统的域名获取站点访问的前缀
	public static String buildLocalhost(boolean ssl, int port, boolean absolutePath, String domain, String code) {
		return (absolutePath ? "//" + domain + (ssl ? (port == 443 ? "" : ":" + port) : (port == 80 ? "" : ":" + port)) : "");
	}

	// 本地开发模式下通过默认的域名获取站点默认访问的前缀
	public static String buildDefaultLocalhost(boolean ssl, int port, boolean absolutePath, String domain, String code) {
		return (absolutePath ? "//" + domain + (ssl ? (port == 443 ? "" : ":" + port) : (port == 80 ? "" : ":" + port)) : "") + "/site/" + code + "-"
				+ SecureUtil.sha1(code);
	}

	// 非本地开发模式下站点默认访问的前缀
	public static String buildDefaultLocalhost(boolean absolutePath, String domain, String code) {
		return (absolutePath ? "//" + domain : "") + "/site/" + code + "-" + SecureUtil.sha1(code);
	}

	// 验证uri前缀，同时如果验证成功返回code，验证失败，返回 null
	public static String validCode(String token) {
		String[] split = token.split("-");
		if (split.length != 2) {
			return null;
		}
		String code = split[0];
		String ttoken = split[1];
		if (SecureUtil.sha1(code).equals(ttoken)) {
			return code;
		}
		return null;
	}

	/**
	 * 生成系统域名放行访问的链接地址
	 * 
	 * @param domain
	 * @param hConfig
	 * @param host
	 * @return
	 */
	public static String getSitePathBySysdomainAccess(String domain, boolean ssl, HConfig hConfig, Host host) {
		return getSitePathBySysdomainAccess(domain, ssl, null, null, hConfig, host);
	}

	public static String getSitePathBySysdomainAccess(String domain, boolean ssl, String lano, HConfig hConfig, Host host) {
		return getSitePathBySysdomainAccess(domain, ssl, lano, null, hConfig, host);
	}

	public static String getSitePathBySysdomainAccess(String domain, boolean ssl, String lano, String uri, HConfig hConfig, Host host) {
		String result = (ssl ? "https" : "http") + "://" + domain + SysDomainAccessVaildUri;
		if (StrUtil.isBlank(uri)) {
			uri = "/";
		}
		if (StrUtil.isNotBlank(lano)) {
			uri = "/" + lano + uri;
		}

		try {
			uri = CryptoJava.en(uri);
		} catch (Exception e) {
		}

		String token = HostConfigUtil.sysdomainAccessPwd(hConfig, host);

		return result + "?uri=" + uri + "&token=" + token;
	}

	public static String getPagePathBySysdomainAccess(String domain, boolean ssl, String lano, SPage sPage, HConfig hConfig, Host host) {
		if (sPage.getType() != null && sPage.getType().shortValue() == (short) 3) {
			String externalPath = getSPageExternalPath(sPage);
			if (StrUtil.startWith(externalPath, "/") && !StrUtil.startWith(externalPath, "//")) {
				return getSitePathBySysdomainAccess(domain, ssl, null, externalPath, hConfig, host);
			} else {
				return externalPath;
			}
		}
		return getSitePathBySysdomainAccess(domain, ssl, lano, getPath(sPage), hConfig, host);
	}

	/**
	 * 通过生成链接，如果是系统域名需要对链接进行访问授权处理
	 * 
	 * @param hDomain
	 * @param lano
	 * @param uri
	 * @param hConfig
	 * @param host
	 * @return
	 */
	public static String getSitePath(HDomain hDomain, boolean ssl, String lano, String uri, HConfig hConfig, Host host) {
		Short domainType = hDomain.getDomainType();
		String domainName = hDomain.getDomainName();
		if (domainType == null || StrUtil.isBlank(domainName)) {
			return null;
		}

		if (domainType.shortValue() == 0) {
			return getSitePathBySysdomainAccess(domainName, ssl, lano, uri, hConfig, host);
		} else {
			String result = "";
			if (ssl) {
				result += "https://";
			} else {
				result += "http://";
			}

			result += domainName;

			if (StrUtil.isNotBlank(lano)) {
				result += "/" + lano;
			}

			result += uri;

			return result;
		}
	}

	/**
	 * 默认域名访问地址
	 * 
	 * @param domain
	 * @return
	 */
	public static String getSitePath(String domain) {
		return "//" + domain + "/";
	}

	/**
	 * 默认域名带语言版本的访问地址
	 * 
	 * @param domain
	 * @param lano
	 * @return
	 */
	public static String getSitePath(String domain, String lano) {
		return "//" + domain + "/" + lano + "/";
	}

	/**
	 * 通过 SPage 获取完整链接路径 //[domain]/[href]
	 * 
	 * @return
	 */
	public static String getFullPath(SPage sPage, String domain) {
		if (sPage.getType().shortValue() == (short) 3) {
			return getSPageExternalPath(sPage);
		}
		return "//" + domain + getPath(sPage);
	}

	/**
	 * 通过 SPage 获取完整链接路径 //[domain]/[lanno]/[href]
	 * 
	 * @return
	 */
	public static String getFullPath(SPage sPage, String domain, String lano) {
		if (sPage.getType().shortValue() == (short) 3) {
			return getSPageExternalPath(sPage);
		}
		return "//" + domain + "/" + lano + getPath(sPage);
	}

	public static String getFullPath(String domain, String path) {
		return "//" + domain + path;
	}

	public static String getFullPath(String domain, String lano, String path) {
		return "//" + domain + "/" + lano + path;
	}

	public static String getFullPath(boolean ssl, int port, String domain) {
		return "//" + domain + (ssl ? (port == 443 ? "" : ":" + port) : (port == 80 ? "" : ":" + port));
	}

	public static String getFullPath(boolean ssl, int port, String domain, String lano) {
		return getFullPath(ssl, port, domain) + "/" + lano;
	}

	/**
	 * 通过 SPage 获取相对链接路径 /[href].html
	 * 
	 * @return
	 */
	public static String getPath(SPage sPage) {
		return getPath(sPage, true);
	}

	/**
	 * SPage sPage, SCategories sCategories, page 为0的获取相对链接url
	 * 
	 * @param sPage
	 * @param sCategories
	 * @return
	 */
	public static String getPath(SPage sPage, SCategories sCategories) {
		return getPath(sPage, sCategories, -1);
	}

	/**
	 * SPage sPage, SCategories sCategories, int page 获取相对链接url
	 * 
	 * @param sPage
	 * @param sCategories
	 * @param page
	 * @return
	 */
	public static String getPath(SPage sPage, SCategories sCategories, int page) {
		return getPath(sPage, sCategories, page, ".html");
	}

	/**
	 * SPage sPage, SCategories sCategories, String page 获取相对链接url
	 * 
	 * @param sPage
	 * @param sCategories
	 * @param page
	 * @return
	 */
	public static String getPath(SPage sPage, SCategories sCategories, String page) {
		return getPath(sPage, sCategories, page, ".html");
	}

	/**
	 * SPage sPage, SArticleSlug sArticleSlug 获取相对链接url
	 * 
	 * @param sPage
	 * @param sArticleSlug
	 * @return
	 */
	public static String getPath(SPage sPage, SArticleSlug sArticleSlug) {
		return getPath(sPage, sArticleSlug, ".html");
	}

	/**
	 * SPage sPage, SPdtable sPdtable 获取相对链接url
	 * 
	 * @param sPage
	 * @param sPdtable
	 * @return
	 */
	public static String getPath(SPage sPage, SPdtable sPdtable) {
		return getPath(sPage, sPdtable, ".html");
	}

	/**
	 * SPage sPage, SCategories sCategories, SPdtable sPdtable 获取相对链接url
	 * 
	 * @param sPage
	 * @param sCategories
	 * @param sPdtable
	 * @return
	 */
	public static String getPath(SPage sPage, SCategories sCategories, SPdtable sPdtable) {
		return getPath(sPage, sCategories, sPdtable, ".html");
	}

	/**
	 * SPage sPage, SProduct product 获取相对链接url
	 * 
	 * @param sPage
	 * @param product
	 * @return
	 */
	public static String getPath(SPage sPage, SProduct product) {
		return getPath(sPage, product, ".html");
	}

	/**
	 * SPage sPage, SCategories sCategories, SProduct product 获取相对链接url
	 * 
	 * @param sPage
	 * @param sCategories
	 * @param product
	 * @return
	 */
	public static String getPath(SPage sPage, SCategories sCategories, SProduct product) {
		return getPath(sPage, sCategories, product, ".html");
	}

	/**
	 * SPage sPage, SArticle article 获取相对链接url
	 * 
	 * @param sPage
	 * @param article
	 * @return
	 */
	public static String getPath(SPage sPage, SArticle article) {
		return getPath(sPage, article, ".html");
	}

	/**
	 * SPage sPage, SCategories sCategories, SArticle article 获取相对链接url
	 * 
	 * @param sPage
	 * @param sCategories
	 * @param article
	 * @return
	 */
	public static String getPath(SPage sPage, SCategories sCategories, SArticle article) {
		return getPath(sPage, sCategories, article, ".html");
	}

	/**
	 * 通过 SPage 获取相对链接路径 /[href][html]
	 * 
	 * @return
	 */
	public static String getPath(SPage sPage, boolean html) {
		if (html) {
			return getPath(sPage, ".html");
		} else {
			return getPath(sPage, "");
		}
	}

	public static String getPath(SSystemItemCustomLink sSystemItemCustomLink) {
		if (sSystemItemCustomLink == null) {
			return "/index.html?NullSSystemCustomLink";
		}
		String pathFinal = sSystemItemCustomLink.getPathFinal();
		String[] pathFinalSplit = pathFinal.split("/");
		List<String> newArrayList = new ArrayList<>(pathFinalSplit.length);
		for (String str : pathFinalSplit) {
			if (StrUtil.isNotBlank(str)) {
				newArrayList.add(URLUtil.encode(str));
			}
		}
		if (CollUtil.isEmpty(newArrayList)) {
			return "/index.html?NullCollect";
		}
		return "/" + CollUtil.join(newArrayList, "/") + ".html";
	}

	/**
	 * 通过 SPage 获取相对链接路径 /[href][html]
	 * 
	 * @return
	 */
	public static String getPath(SPage sPage, String suffix) {
		if (sPage.getType().shortValue() == (short) 0) {
			// 引导页
			return "/";
		} else if (sPage.getType().shortValue() == (short) 1) {
			// 普通页面
			return getSPageCommonPath(sPage) + suffix;
		} else if (sPage.getType().shortValue() == (short) 2) {
			// 系统页面
			return getSPageCommonPath(sPage) + suffix;
		} else if (sPage.getType().shortValue() == (short) 3) {
			// 外链接页面
			return getSPageExternalPath(sPage);
		} else if (sPage.getType().shortValue() == (short) 4) {
			// 内链接页面
			throw new RuntimeException("未完成!");
		}
		return "/";
	}

	/**
	 * 通过 SPage、SCategories 获取相对链接路径 /[sPage]/[sCategories][html]
	 * 
	 * @param sPage
	 * @param sCategories
	 * @param page
	 * @param suffix
	 * @return
	 */
	public static String getPath(SPage sPage, SCategories sCategories, int page, String suffix) {
		String path = getPath(sPage, "");
		String rewrite = sCategories != null ? (StringUtils.hasText(sCategories.getRewrite()) ? sCategories.getRewrite() : String.valueOf(sCategories.getId()))
				: "index";
		path = path + "/" + rewrite;
		if (page >= 0) {
			path = path + "-" + page;
		}
		return path + suffix;
	}

	/**
	 * 通过 SPage、SCategories 获取相对链接路径 /[sPage]/[sCategories][html]
	 * 
	 * @param sPage
	 * @param sCategories
	 * @param page
	 * @param suffix
	 * @return
	 */
	public static String getPath(SPage sPage, SCategories sCategories, String page, String suffix) {
		String path = getPath(sPage, "");
		String rewrite = sCategories != null ? (StringUtils.hasText(sCategories.getRewrite()) ? sCategories.getRewrite() : String.valueOf(sCategories.getId()))
				: "index";
		path = path + "/" + rewrite + "-" + page;
		return path + suffix;
	}

	/**
	 * 通过 SPage、SPdtable 获取相对链接路径 /[sPage]/item/[sPdtable][html]
	 * 
	 * @param sPage
	 * @param sPdtable
	 * @param suffix
	 * @return
	 */
	public static String getPath(SPage sPage, SPdtable sPdtable, String suffix) {
		return getPath(sPage, null, sPdtable, suffix);
	}

	/**
	 * 通过 SPage、SCategories、sPdtable 获取相对链接路径
	 * /[sPage]/[sCategories]/[sPdtable][html]
	 * 
	 * @param sPage
	 * @param sCategories
	 * @param sPdtable
	 * @param suffix
	 * @return
	 */
	public static String getPath(SPage sPage, SCategories sCategories, SPdtable sPdtable, String suffix) {
		String path = getPath(sPage, "");
		String rewrite = sCategories != null ? (StringUtils.hasText(sCategories.getRewrite()) ? sCategories.getRewrite() : String.valueOf(sCategories.getId()))
				: "item";
		path = path + "/" + rewrite + "/" + sPdtable.getId();
		return path + suffix;
	}

	/**
	 * 通过 SPage、SProduct 获取相对链接路径 /[sPage]/item/[product][html]
	 * 
	 * @param sPage
	 * @param product
	 * @param suffix
	 * @return
	 */
	public static String getPath(SPage sPage, SProduct product, String suffix) {
		return getPath(sPage, null, product, suffix);
	}

	/**
	 * 通过 SPage、SCategories、SProduct 获取相对链接路径 /[sPage]/[sCategories]/[product][html]
	 * 
	 * @param sPage
	 * @param sCategories
	 * @param product
	 * @param suffix
	 * @return
	 */
	public static String getPath(SPage sPage, SCategories sCategories, SProduct product, String suffix) {
		String path = getPath(sPage, "");
		String rewrite2 = sCategories != null ? (StringUtils.hasText(sCategories.getRewrite()) ? sCategories.getRewrite() : String.valueOf(sCategories.getId()))
				: "item";
		String rewrite = product.getRewrite();
		path = path + "/" + rewrite2;
		if (StringUtils.hasText(rewrite)) {
			path = path + "/" + rewrite;
		} else {
			path = path + "/" + product.getId();
		}
		return path + suffix;
	}

	/**
	 * 通过 SPage、SArticle 获取相对链接路径 /[sPage]/item/[article][html]
	 * 
	 * @param sPage
	 * @param product
	 * @param suffix
	 * @return
	 */
	public static String getPath(SPage sPage, SArticle article, String suffix) {
		return getPath(sPage, null, article, suffix);
	}

	/**
	 * 通过 SPage、SCategories、SArticle 获取相对链接路径 /[sPage]/[sCategories]/[article][html]
	 * 
	 * @param sPage
	 * @param sCategories
	 * @param article
	 * @param suffix
	 * @return
	 */
	public static String getPath(SPage sPage, SCategories sCategories, SArticle article, String suffix) {
		String path = getPath(sPage, "");
		String rewrite2 = sCategories != null ? (StringUtils.hasText(sCategories.getRewrite()) ? sCategories.getRewrite() : String.valueOf(sCategories.getId()))
				: "item";
		String rewrite = article.getRewrite();
		path = path + "/" + rewrite2;
		if (StringUtils.hasText(rewrite)) {
			path = path + "/" + rewrite;
		} else {
			path = path + "/" + article.getId();
		}
		return path + suffix;
	}

	/**
	 * 通过 SPage、SArticleSlug 获取相对链接路径 /[sPage]/[sArticleSlug][html]
	 * 
	 * @param sPage
	 * @param sArticleSlug
	 * @param suffix
	 * @return
	 */
	public static String getPath(SPage sPage, SArticleSlug sArticleSlug, String suffix) {
		String path = getPath(sPage, "");
		path = path + "/item/" + sArticleSlug.getId();
		return path + suffix;
	}

	/**
	 * 获取外链接页面的链接
	 * 
	 * @return
	 */
	public static String getSPageExternalPath(SPage sPage) {
		if (sPage.getUrl() == null) {
			return "/#";
		}
		ObjectMapper objectMapper = new ObjectMapper();
		JavaType valueType = objectMapper.getTypeFactory().constructParametricType(HashMap.class, String.class, Object.class);
		try {
			@SuppressWarnings("unchecked")
			Map<String, Object> readValue = (Map<String, Object>) objectMapper.readValue(sPage.getUrl(), valueType);
			if (StringUtils.isEmpty(readValue.get("external"))) {
				return "/#";
			}
			return (String) readValue.get("external");
		} catch (IOException e) {
			e.printStackTrace();
		}
		return "/#";
	}

	/**
	 * 获取普通页面以及系统页面的链接
	 * 
	 * @return
	 */
	public static String getSPageCommonPath(SPage sPage) {
		if (StringUtils.isEmpty(sPage.getRewrite())) {
			return "/" + String.valueOf(sPage.getId());
		}
		return "/" + sPage.getRewrite();
	}

	/**
	 * 普通链接增加参数
	 * 
	 * @param url
	 * @param params
	 * @return
	 */
	public static String appendParams(String url, Map<String, String> params) {
		if (StringUtils.isEmpty(url)) {
			return "";
		} else if (CollectionUtils.isEmpty(params)) {
			return url.trim();
		} else {
			StringBuffer sb = new StringBuffer("");
			Set<String> keys = params.keySet();
			for (String key : keys) {
				sb.append(key).append("=").append(params.get(key)).append("&");
			}
			sb.deleteCharAt(sb.length() - 1);

			url = url.trim();
			int length = url.length();
			int index = url.indexOf("?");
			if (index > -1) {
				if ((length - 1) == index) {
					url += sb.toString();
				} else {
					url += "&" + sb.toString();
				}
			} else {
				url += "?" + sb.toString();
			}
			return url;
		}
	}

	/**
	 * 向url链接追加参数(单个)
	 * 
	 * @param url
	 * @param name  String
	 * @param value String
	 * @return
	 */
	public static String appendParam(String url, String name, String value) {
		if (StringUtils.isEmpty(url)) {
			return "";
		} else if (StringUtils.isEmpty(name)) {
			return url.trim();
		} else {
			Map<String, String> params = new HashMap<String, String>();
			params.put(name, value);
			return appendParams(url, params);
		}
	}

	/**
	 * 移除url链接的多个参数
	 * 
	 * @param url        String
	 * @param paramNames String[]
	 * @return
	 */
	public static String removeParams(String url, String... paramNames) {
		if (StringUtils.isEmpty(url)) {
			return "";
		} else if (ArrayUtils.isEmpty(paramNames)) {
			return url.trim();
		} else {
			url = url.trim();
			int length = url.length();
			int index = url.indexOf("?");
			if (index > -1) {
				if ((length - 1) == index) {
					return url;
				} else {
					String baseUrl = url.substring(0, index);
					String paramsString = url.substring(index + 1);
					String[] params = paramsString.split("&");
					if (!ArrayUtils.isEmpty(paramNames)) {
						Map<String, String> paramsMap = new HashMap<>();
						for (String param : params) {
							if (!StringUtils.isEmpty(param)) {
								String[] oneParam = param.split("=");
								String paramName = oneParam[0];
								int count = 0;
								for (int i = 0; i < paramNames.length; i++) {
									if (paramNames[i].equals(paramName)) {
										break;
									}
									count++;
								}
								if (count == paramNames.length) {
									paramsMap.put(paramName, (oneParam.length > 1) ? oneParam[1] : "");
								}
							}
						}
						if (!CollectionUtils.isEmpty(paramsMap)) {
							StringBuffer paramBuffer = new StringBuffer(baseUrl);
							paramBuffer.append("?");
							Set<String> set = paramsMap.keySet();
							for (String paramName : set) {
								paramBuffer.append(paramName).append("=").append(paramsMap.get(paramName)).append("&");
							}
							paramBuffer.deleteCharAt(paramBuffer.length() - 1);
							return paramBuffer.toString();
						}
						return baseUrl;
					}
				}
			}
			return url;
		}
	}
}
